package com.speakit.tts.engine;

import java.io.UnsupportedEncodingException;
import java.util.LinkedList;

import com.speakit.tts.foc.utils.L;
import com.speakit.tts.foc.utils.Utils;

import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

public class TTSAnnouncer extends Thread {

	public static TTSAnnouncer instance = null;
	/*
	 * {英语男, 英语女}, {中文1男, 中文1女}, {中文2男, 中文2女}, ...
	 */
	public static final String[] libPath = {

	Utils.voiceLib + "mandarin/xiaotian.dat",
			Utils.voiceLib + "mandarin/xiaoyan.dat",
			Utils.voiceLib + "english/Rose.dat", };

	OnReadListener onReadListener = null;
	MyReaderListener myReaderListener=null;
	SetInputTextProc inputTextProc = null;
	GetOutputVoiceProc outputVoiceProc = null;
	private static boolean stopVoice = false;
	public boolean isInitSuccess = true;
	private static Fan2Jian fan2Jian = null;
	/** 引擎调用句柄 */
	private LongInt mHandle;
	public PlayOption playOption;
	public static final int PLAY = 0;
	private AudioTrack audioTrack;
	/** 播放器最小缓存大小 */
	int iMinBufSize;
	private Handler messageHandler;
	/** 开始转换 */
	static int START_Synthesize = 0;
	private boolean isInitFinish = false;

	private Context mContext;
	public TTSAnnouncer(Context context) {
		mContext=context;
		inputTextProc = new SetInputTextProc();
		outputVoiceProc = new GetOutputVoiceProc();
		fan2Jian = new Fan2Jian();
		if (!(isInitSuccess = this.initTTSEngine())) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					isInitSuccess = TTSAnnouncer.this.initTTSEngine();
					if (!TTSAnnouncer.this.initAudioTrack()) {
						return;
					}
					TTSAnnouncer.this.start();
					TTSAnnouncer.instance = TTSAnnouncer.this;
				}
			}).start();
			return;
		}
		isInitFinish = isInitSuccess;
		if (!TTSAnnouncer.this.initAudioTrack()) {
			isInitFinish = false;
			return;
		}
		this.start();
		instance = this;

		this.setPriority(MAX_PRIORITY);
	}

	/** TTS初始化 */
	private boolean initTTSEngine() {
		playOption = new PlayOption();
		String szENLib = libPath[2];
		String szCNLib = libPath[playOption.getSex()];
		mHandle = new LongInt();
		int initCode = TTSEngine.hwTTSInit(mContext.getAssets(),szCNLib, szENLib, "", mHandle);
		if (initCode != 0) {
			if (this.onReadListener != null) {
				this.onReadListener.onInitEnginError(initCode);
			}
			return false;
		}
		TTSEngine.hwTTSSetParam(mHandle.nValue, TTSEngine.PARAM_READ_TONE,
				playOption.getReadTone());
		TTSEngine.hwTTSSetParam(mHandle.nValue, TTSEngine.PARAM_READ_SPEED,
				playOption.getReadSpeed() + playOption.getLanguageType() * 2);
		TTSEngine.hwTTSSetParam(mHandle.nValue, TTSEngine.PARAM_READ_VOICE, 50);

		int nError = TTSEngine.hwTTSSetInputTextCB(mHandle.nValue,
				inputTextProc);
		nError = TTSEngine.hwTTSSetOutputVoiceCB(mHandle.nValue,
				outputVoiceProc);
		if (nError != 0) {
		}
		return true;
	}

	/** 初始化播放器信息 */
	private boolean initAudioTrack() {
		boolean initSuccess = true;
		if (this.audioTrack == null) {
			iMinBufSize = AudioTrack.getMinBufferSize(18000,
					AudioFormat.CHANNEL_CONFIGURATION_MONO,
					AudioFormat.ENCODING_PCM_16BIT);
			try {
				this.audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
						18000, AudioFormat.CHANNEL_CONFIGURATION_MONO,
						AudioFormat.ENCODING_PCM_16BIT, iMinBufSize,
						AudioTrack.MODE_STREAM);
				L.l("=======init====" + this.audioTrack);
			} catch (Exception e) {
				initSuccess = false;
			}
		}
		return initSuccess;
	}

	public void pauseAudio() {
		this.audioTrack.pause();
	}

	public void restartAudio() {
		this.audioTrack.play();
	}

	public boolean isPlaying() {
		if (this.audioTrack.getPlayState() != AudioTrack.PLAYSTATE_PLAYING) {
			return false;
		} else {
			return true;
		}
	}

	public void run() {
		Looper.prepare();
		messageHandler = new Handler() {
			public void handleMessage(Message msg) {
				if (getVoiceStopFlag()) {
					onReadListener.onUserStop();
					return;
				}
				if (msg.what == PLAY) {
					if (audioTrack.getPlayState() != AudioTrack.PLAYSTATE_PLAYING
							&& !getVoiceStopFlag()) {
						audioTrack.play();
					}
					PlayMessage returnDate = (PlayMessage) msg.obj;
					if ((returnDate.byteBuffer.arrBytes != null)) {
						if (!getVoiceStopFlag()) {
							audioTrack.write(returnDate.byteBuffer.arrBytes, 0,
									returnDate.byteBuffer.arrBytes.length);
						}
					}
					if (!getVoiceStopFlag() && returnDate.finalMsg) {
						onReadListener.onReadEnd();
						TTSEngine.hwTTSSynthStop(mHandle.nValue);
						setVoiceStopFlag(true);
						audioTrack.stop();
						audioTrack.flush();

						if (needToSynthesizeCache != null
								&& needToSynthesizeCache.size() > 0) {
							startLoadCache = true;
							synchronized (TTSEnginlock) {
								TTSEnginlock.notify();
							}
						}
						while (voiceCache == null || voiceCache.size() == 0) {
							try {
								Thread.sleep(50);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
							if (getVoiceStopFlag()) {
								return;
							}
						}
						if (voiceCache != null && voiceCache.size() > 0) {
							// 继续读下一句
							Message message = new Message();
							message.what = PLAY;

							PlayMessage pm = new PlayMessage();
							pm.finalMsg = true;

							ByteBuffer bb = new ByteBuffer();
							bb.arrBytes = voiceCache.removeFirst();
							pm.byteBuffer = bb;

							message.obj = pm;
							messageHandler.sendMessage(message);
						}

					}

					if (!getVoiceStopFlag()) {
						onReadListener.onPlaying();
					} else {
						onReadListener.onUserStop();
					}
				}
			}

		};
		Looper.loop();

	}

	public void setOnReadListener(OnReadListener onReadListener) {
		this.onReadListener = onReadListener;
	}
	
	public void setMyReaderListener(MyReaderListener listener)
	{
		this.myReaderListener=listener;
	}

	public void setChange() {
		stopVoice();
		if (mHandle != null) {
			TTSEngine.hwTTSSynthStop(mHandle.nValue);
			TTSEngine.hwTTSEnd(mHandle.nValue);
		}
		isInitFinish = initTTSEngine();
//		onReadListener.onSettingChange();
		playVoice(TTSPlayer.WELCOME_TEXT);
	}

	private boolean getVoiceStopFlag() {
		return stopVoice;
	}

	private void setVoiceStopFlag(boolean flag) {
		stopVoice = flag;
	}

	/**
	 * 阅读语音,阅读结束后会回调监听器的onReadEnd();
	 * 
	 * @param text
	 */

	public void playVoice(String text) {
		setVoiceStopFlag(false);
		isInitFinish = true;
		text = fan2Jian.conver(text, 0);
		try {
			inputTextProc.setInputByte(text.getBytes("GBK"));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		handler.sendEmptyMessage(START_Synthesize);
	}

	/** 停止播放 */
	public void stopVoice() {
		L.l("====stop voice===");
		setVoiceStopFlag(true);
		audioTrack.stop();
		audioTrack.flush();
		needToSynthesizeCache = new LinkedList<byte[]>();
		voiceCache = new LinkedList<byte[]>();
	}

	/** 完成Text->VoiceData调用 */
	private void onVoiceDataOutputFinish(ByteBuffer returnDate, boolean isEnd) {
		if (startLoadCache) {
			// 将解析内容放入缓存
			voiceHolder.arrBytes = Utils.join(voiceHolder.arrBytes,
					returnDate.arrBytes);
			if (isEnd) {
				if (voiceHolder.arrBytes != null) {
					voiceCache.add(voiceHolder.arrBytes.clone());
				}
				voiceHolder = new ByteBuffer();
			}
		} else {
			// 解析完毕直接播放
			Message message = new Message();
			message.what = PLAY;
			PlayMessage playMessage = new PlayMessage();
			playMessage.byteBuffer = returnDate;
			playMessage.finalMsg = isEnd;
			message.obj = playMessage;
			messageHandler.sendMessage(message);
		}
	}
	
	
	
	public interface MyReaderListener{
		public void readEnd();
	}
	
	
	
	
	

	/**
	 * ******* 发音监听器，用于监听发音器的状态
	 */
	public interface OnReadListener {

		/**
		 * 初始化引擎失败回调
		 * 
		 * @param ErrorCode
		 *            初始化失败返回代码
		 */
		public void onInitEnginError(int ErrorCode);

		public void onSettingChange();

		/**
		 * 阅读完毕回调
		 */
		public void onReadEnd();

		/**
		 * 被stop时的回调
		 */
		public void onUserStop();

		public void onPlaying();

		/**
		 * 字串给读完时相应回调
		 */
		public void onSubStringReadEnd();
	}

	/** 引擎文本输入接口 */
	private class SetInputTextProc implements ITTSInputTextProc {

		/** 设置需要输入引擎进行分析的内容 */
		public void setInputByte(byte[] inputByte) {
			text = inputByte;
		}

		byte[] text = new byte[0];

		@Override
		public int callBackProc(ByteBuffer pText, LongInt piSize) {

			L.l("========input===text==");
			if (getVoiceStopFlag()) {
				TTSEngine.hwTTSSynthStop(mHandle.nValue);
				onReadListener.onUserStop();
				return 0;
			}
			if (startLoadCache) {
				try {
					byte[] cache = needToSynthesizeCache.removeFirst();
					pText.arrBytes = cache;
				} catch (Exception e) {
					TTSEngine.hwTTSSynthStop(mHandle.nValue);
					e.printStackTrace();
					return 0;
				}
			} else {
				pText.arrBytes = text;
			}
			piSize.nValue = pText.arrBytes.length;
			return 0;
		}
	}

	Object TTSEnginlock = new Object();
	/** 需要预加载的语音 */
	LinkedList<byte[]> needToSynthesizeCache = new LinkedList<byte[]>();

	LinkedList<byte[]> voiceCache = new LinkedList<byte[]>();

	private ByteBuffer voiceHolder = new ByteBuffer();

	private ByteBuffer returnDate = new ByteBuffer();

	int idx = 0;

	/** 加载预处理文字 */
	boolean startLoadCache = false;

	/** 引擎语音信息输出接口 */
	private class GetOutputVoiceProc implements ITTSOutputVoiceProc {

		int MAX_COUNT = 3;

		@Override
		public int callBackProc(long iOutputFormat, ByteBuffer pVoiceData,
				long iVoiceSize) {
			synchronized (TTSEnginlock) {
				if (getVoiceStopFlag()) {
					TTSEngine.hwTTSSynthStop(mHandle.nValue);
					onReadListener.onUserStop();
					returnDate = new ByteBuffer();
					voiceHolder = new ByteBuffer();
					idx = 0;
					return 0;
				}

				if (iVoiceSize == 0) {
					// 接收完毕, 停止引擎
					idx = 0;
					TTSAnnouncer.this.onVoiceDataOutputFinish(returnDate, true);
					returnDate = new ByteBuffer();
					if (needToSynthesizeCache == null
							|| needToSynthesizeCache.size() == 0) {
						try {
							TTSEnginlock.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					} else {
						startLoadCache = true;
					}
				} else {
					idx = (idx + 1) % MAX_COUNT;
					returnDate.arrBytes = Utils.join(returnDate.arrBytes,
							pVoiceData.arrBytes);
					if (idx == 0) {
						TTSAnnouncer.this.onVoiceDataOutputFinish(returnDate,
								false);
						returnDate = new ByteBuffer();
					}
				}
			}
			return 0;
		}
	}

	private class PlayMessage {
		ByteBuffer byteBuffer;
		boolean finalMsg = false;
	}

	public Handler handler = new Handler() {
		public void handleMessage(Message msg) {
			L.l("====00===synthesize===" + isInitFinish);
			if (msg.what == START_Synthesize) {

				while (!isInitFinish) {
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				synthesizeVoice();
			}
		}
	};

	public void synthesizeVoice() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				L.l("=======syn=====it====");
				// TODO Auto-generated method stub
				TTSEngine.hwTTSSynthesize(mHandle.nValue);
			}
		}).start();
	}

}
